package com.xxl.mq.client.factory.impl;

import com.xxl.mq.client.consumer.IMqConsumer;
import com.xxl.mq.client.consumer.annotation.MqConsumer;
import com.xxl.mq.client.factory.XxlMqClientFactory;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.core.env.Environment;

/**
 * @author xuxueli 2018-11-18 21:18:10
 */
public class XxlMqSpringClientFactory implements ApplicationContextAware, DisposableBean {

    // ---------------------- param  ----------------------

    private String adminAddress;
    private String accessToken;

    public void setAdminAddress(String adminAddress) {
        this.adminAddress = adminAddress;
    }
    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    // XxlMqClientFactory
    private XxlMqClientFactory xxlMqClientFactory;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Environment environment=applicationContext.getEnvironment();
        // load consumer from spring
        List<IMqConsumer> consumerList = new ArrayList<>();

        Map<String, Object> serviceMap = applicationContext.getBeansWithAnnotation(MqConsumer.class);
        if (serviceMap!=null && serviceMap.size()>0) {
            for (Object serviceBean : serviceMap.values()) {
                if (serviceBean instanceof IMqConsumer) {
                    //增加spring注解支持
                    MqConsumer mqConsumer = setGroupOrOpen((IMqConsumer) serviceBean, environment);
                    if(MqConsumer.OPEN.equalsIgnoreCase(mqConsumer.open())){
                        consumerList.add((IMqConsumer) serviceBean);
                    }
                }
            }
        }

        // init
        xxlMqClientFactory = new XxlMqClientFactory();

        xxlMqClientFactory.setAdminAddress(adminAddress);
        xxlMqClientFactory.setAccessToken(accessToken);
        xxlMqClientFactory.setConsumerList(consumerList);

        xxlMqClientFactory.init();
    }


    /**
     * 提取 Environment 数据
     * @param consumerHandler
     * @param environment
     * @return
     */
    private MqConsumer setGroupOrOpen(IMqConsumer consumerHandler, Environment environment){
        MqConsumer mqConsumer = consumerHandler.getClass().getAnnotation(MqConsumer.class);
        try {
            if(mqConsumer.group().indexOf("$")!=-1 || mqConsumer.open().indexOf("$")!=-1){
                //获取 foo 这个代理实例所持有的 InvocationHandler
                InvocationHandler invocationHandler = Proxy.getInvocationHandler(mqConsumer);
                // 获取 AnnotationInvocationHandler 的 memberValues 字段
                Field declaredField = invocationHandler.getClass().getDeclaredField("memberValues");
                // 因为这个字段事 private final 修饰，所以要打开权限
                declaredField.setAccessible(true);
                // 获取 memberValues
                Map memberValues = (Map) declaredField.get(invocationHandler);
                // 修改 value 属性值
                if(mqConsumer.group().indexOf("$")!=-1) {
                    memberValues.put("group", environment.getProperty(setText(mqConsumer.group(), "{", "}")));
                }
                if(mqConsumer.open().indexOf("$")!=-1) {
                    memberValues.put("open", environment.getProperty(setText(mqConsumer.open(), "{", "}")));
                }
                if(mqConsumer.topic().indexOf("$")!=-1) {
                    memberValues.put("topic", environment.getProperty(setText(mqConsumer.topic(), "{", "}")));
                }
            }
        }catch (Exception e){
            throw new RuntimeException("xxl-mq, MqConsumer("+ mqConsumer.getClass() +"), group 写入失败.");
        }
        return mqConsumer;
    }

    public static String setText(String content, String s, String e) {
        int start = 0;
        int end = 0;
        if (content.indexOf(s) != -1 && content.indexOf(e) != -1) {
            start = content.indexOf(s) + 1;
            end = content.indexOf(e) ;
            if (start < end) {
                return content.substring(start, end);
            }
            return content;
        } else {
            return content;
        }
    }

    @Override
    public void destroy() throws Exception {
        xxlMqClientFactory.destroy();
    }

}
